﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Elentok.Common;
using AMail.Common.Interfaces.Data;
using Elentok.Common.Async;

namespace AMail.Common
{
  public static class AMailExtensions
  {
    /// <summary>
    /// Returns true if this folder is a descendand of <paramref name="folder"/>.
    /// </summary>
    /// <param name="folder"></param>
    /// <returns></returns>
    public static bool IsDescendantOf(this IMailFolder folder, IMailFolder greatParent)
    {
      if (folder.ParentFolder == greatParent)
        return true;

      if (folder.ParentFolder == null)
        return false;

      return folder.ParentFolder.IsDescendantOf(greatParent);
    }

    /// <summary>
    /// Gets the descendant folder by the given name (can be separated by '\\' or '/')
    /// (if the subfolder doesn't exist, it will be created)
    /// </summary>
    /// <param name="relativePath"></param>
    /// <returns></returns>
    public static IMailFolder GetOrCreateSubfolder(this IMailFolder folder, string relativePath)
    {
      relativePath = relativePath.Replace('\\', '/');
      string[] subfolders = relativePath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
      if (subfolders.Length == 0)
        return folder;

      return folder.GetOrCreateSubfolder(subfolders, 0);
    }

    /// <summary>
    /// Returns the recursive message count
    /// </summary>
    /// <returns></returns>
    public static int CountMessages(this IMailFolder folder)
    {
      int count = folder.Messages.Count;
      foreach (IMailFolder subfolder in folder.Subfolders)
        count += subfolder.CountMessages();
      return count;
    }

    /// <summary>
    /// Gets the descendant folder by the given name (can be separated by '\\' or '/')
    /// (if the subfolder doesn't exist, it will be created)
    /// </summary>
    /// <param name="subfolders"></param>
    /// <param name="subfolders"></param>
    /// <returns></returns>
    private static IMailFolder GetOrCreateSubfolder(this IMailFolder folder, string[] subfolders, int startIndex)
    {
      if (startIndex >= subfolders.Length)
        return folder;

      string subfolderName = subfolders[startIndex];
      IMailFolder subfolder = folder.Subfolders.FirstOrDefault(f => f.Name == subfolderName);
      if (subfolder == null)
      {
        subfolder = folder.CreateSubfolder(subfolderName);
      }

      return subfolder.GetOrCreateSubfolder(subfolders, startIndex + 1);
    }

    /// <summary>
    /// Copies a folder from one archive to another (recursivly with all messages and subfolders)
    /// </summary>
    /// <param name="sourceFolder"></param>
    /// <param name="targetFolder"></param>
    /// <param name="targetArchive"></param>
    /// <param name="totalMessages">The total number of messages to be copied</param>
    /// <param name="currentMessageIndex">The last index of the copied message</param>
    /// <param name="progressNotifier"></param>
    public static int CopyFolderTo(this IMailFolder sourceFolder, IMailFolder targetFolder, int totalMessages, int currentMessageIndex, IAsyncProgressNotifier progressNotifier)
    {
      if (sourceFolder.OwnerArchive == targetFolder.OwnerArchive)
        throw new Exception("The source and target folders must have a different owner archive");

      #region Copy the messages in "sourceFolder"
      foreach (IMailMessage message in sourceFolder.Messages)
      {
        if (progressNotifier != null)
          progressNotifier.NotifyProgress((currentMessageIndex++ * 100 / totalMessages), "Copying message " + currentMessageIndex + " out of " + totalMessages + "...");

        IMailMessage newMessage = message.Clone();
        newMessage.ParentFolder = targetFolder;
      }
      #endregion

      #region Copy the subfolders of "sourceFolder" (recursively)
      foreach (IMailFolder sourceSubfolder in sourceFolder.Subfolders)
      {
        IMailFolder targetSubfolder = targetFolder.CreateSubfolder(sourceSubfolder.Name);
        currentMessageIndex = sourceSubfolder.CopyFolderTo(targetSubfolder, totalMessages, currentMessageIndex, progressNotifier);
      }
      #endregion

      return currentMessageIndex;
    }

    /// <summary>
    /// Finds all of the messages in the specified folder (recursive)
    /// that matches the specified filter and puts them in <paramref name="result"/>
    /// </summary>
    /// <param name="folder"></param>
    /// <param name="filter"></param>
    /// <param name="result"></param>
    public static void FindMessages(this IMailFolder folder, Predicate<IMailMessage> filter, List<IMailMessage> result)
    {
      foreach (IMailMessage message in folder.Messages)
      {
        if (filter(message))
          result.Add(message);
      }

      foreach (IMailFolder subfolder in folder.Subfolders)
        subfolder.FindMessages(filter, result);
    }

    /// <summary>
    /// Finds all of the messages in the specified folder (recursive)
    /// that matches the specified filter and returns them.
    /// </summary>
    /// <param name="folder"></param>
    /// <param name="filter"></param>
    public static List<IMailMessage> FindMessages(this IMailFolder folder, Predicate<IMailMessage> filter)
    {
      List<IMailMessage> messages = new List<IMailMessage>();
      folder.FindMessages(filter);
      return messages;
    }

    /// <summary>
    /// Finds all of the messages in the specified folder (recursive)
    /// and puts them in <paramref name="result"/>
    /// </summary>
    /// <param name="folder"></param>
    /// <param name="result"></param>
    public static void FindAllMessages(this IMailFolder folder, List<IMailMessage> result)
    {
      result.AddRange(folder.Messages);

      foreach (IMailFolder subfolder in folder.Subfolders)
        subfolder.FindAllMessages(result);
    }

  }
}
